#include "LHParser.h"

#include "parser.h"
#include "tree.h"
#include <xmlmemory.h>
#include <map>
#include "FileData.h"

class SpriteInfo
{
public:
	SpriteInfo(){};
	~SpriteInfo(){};
	
	std::map<std::string, std::string> properties;
	std::map<std::string, std::string> physicProperties;
	std::vector<std::vector<std::string> > fixtures;
};

class JointInfo
{
public:
	JointInfo(){};
	~JointInfo(){};
	std::map<std::string, std::string> properties;
};

class LHInfo
{
public:
	static LHInfo* getInstance(){
		if(0 == instance){
			instance = new LHInfo();
			return instance;
		}else{
			return instance;
		}
	}
	void pushNewSpriteInfo(){
		lhSprites.push_back(new SpriteInfo());
		printf("set pushNewSpriteInfo\n");
	}
	void setBeginSpriteProperty(){
		readSprites = true; readJoints = false; readSpritesPhysic = false;
		canPushValueForCurrentKey = false; isDict = false;		
	}
	void setBeginSpritePhysic(){
		readSpritesPhysic = true; readSprites = false; readJoints = false;
		canPushValueForCurrentKey = false; isDict = false;
	}
	void setBeginFixtures(){
		readFixture = true; readJoints = false; fixArray = 0;
		canPushValueForCurrentKey = false;
	}
	void addFixtureArray(){
		if(readFixture){
			printf("add fixture array\n");
			fixArray++;
		}
		curFixture.clear();
	}	
	void substractFixtureArray(){
		if(readFixture){
			printf("substract fixture array\n");
			fixArray--;
		}
		if(fixArray == 1){
			currentLHSprite()->fixtures.push_back(curFixture);
			curFixture.clear();
			printf("-------------------------------------\n");
		}
		if(fixArray == 0)
			readFixture = false;
	}	
	void setReadJoint(bool value){
		printf("set read joint\n");
		readJoints = value;
	}
	void pushNewJointInfo(){
		if(readJoints){
			printf("push new Joint info\n");
			lhJoints.push_back(new JointInfo());
		}
	}
	void setIsDict(bool value){
		isDict = value;
		if(value == false){
			readSprites= false;
			readSpritesPhysic = false;
		}		
		if(isDict && readJoints)
			pushNewJointInfo();
		canPushValueForCurrentKey = false;
	}
	void setCanPushValue(bool value){
		if(readSprites || readJoints || readSpritesPhysic)
			canPushValueForCurrentKey = value;
		else {
			canPushValueForCurrentKey = false;
		}
	}
	void setIsKey(bool value){
		isKey = value;
		canPushValueForCurrentKey = false;
	}
	void setValue(const std::string& value){
		if(!isDict)
			return;
		if(isKey){
			setCurrentKey(value);
			return;
		}
		if(readFixture){
			if(fixArray ==2){
				curFixture.push_back(value);
				printf("Fixture: %s\n", value.c_str());
			}
			return;
		}
		if(canPushValueForCurrentKey && readSprites){
			printf("PROPER-> %s %s\n", currentKey.c_str(), value.c_str());
			currentLHSprite()->properties[currentKey] = value;
			canPushValueForCurrentKey = false;
			return;
		}
		else if(canPushValueForCurrentKey && readSpritesPhysic){
			printf("PHYSIC-> %s %s\n", currentKey.c_str(), value.c_str());
			currentLHSprite()->physicProperties[currentKey] = value;
			canPushValueForCurrentKey = false;
			return;			
		}		
		else if (canPushValueForCurrentKey && readJoints){
			printf("JOINT-> %s %s\n", currentKey.c_str(), value.c_str());
			currentLHJoint()->properties[currentKey] = value;
			canPushValueForCurrentKey = false;
			return;
		}
	}
	~LHInfo(){};
private:
	LHInfo(): canPushValueForCurrentKey(false),isDict(false),readSprites(false),
			  readSpritesPhysic(false),readFixture(false), fixArray(0), readJoints(false),
			  isKey(false){};
	static LHInfo *instance;
	std::string currentKey;
	bool canPushValueForCurrentKey; bool isDict; bool readSprites;bool readSpritesPhysic;
	bool readFixture; int  fixArray; bool readJoints; bool isKey;
	std::vector<SpriteInfo*> lhSprites;
	std::vector<JointInfo*> lhJoints;
	std::vector<std::string> curFixture;
	
	SpriteInfo* currentLHSprite(){
		return lhSprites[lhSprites.size()-1];
	}
	JointInfo* currentLHJoint(){
		return lhJoints[lhJoints.size()-1];
	}
	void setCurrentKey(const std::string& key){
		currentKey = key;
		canPushValueForCurrentKey = false;
	}
};
LHInfo* LHInfo::instance = NULL;


void read_startElement(void *ctx, const xmlChar *name, const xmlChar **atts);
void read_endElement(void *ctx, const xmlChar *name);
void read_characters(void *ctx, const xmlChar *ch, int len);

using namespace cocos2d;

class LHParser
{
public:
	LHParser(){};
	virtual ~LHParser(){};
	
	bool parsePLIST(const char* file){
		cocos2d::FileData data;
		unsigned long size = 0;
		char *pBuffer = (char*) data.getFileData(file, "r", &size);
		if (!pBuffer){
			return false;
		}
	
		LIBXML_TEST_VERSION
		xmlSAXHandler saxHandler;
		memset( &saxHandler, 0, sizeof(saxHandler) );
		saxHandler.initialized = XML_SAX2_MAGIC;
		saxHandler.startElement = &read_startElement;
		saxHandler.endElement = &read_endElement;
		saxHandler.characters = &read_characters;
	
		int result = xmlSAXUserParseMemory( &saxHandler, this, pBuffer, size );
		if ( result != 0 ){
			return false;
		}
		xmlCleanupParser();
		xmlMemoryDump();	
		return true;
	}
};
void read_startElement(void *ctx, const xmlChar *name, const xmlChar **atts){	
	std::string elementName = (char*)name;
//	printf("StartElement %s\n", elementName.c_str());	
	if(elementName == "key"){
		LHInfo::getInstance()->setIsKey(true);
	}
	else if( elementName == "dict"){
		LHInfo::getInstance()->setIsDict(true);
	}
	else if(elementName == "array"){
		LHInfo::getInstance()->addFixtureArray();
	}	
	else {
		LHInfo::getInstance()->setCanPushValue(true);
	}
}
void read_endElement(void *ctx, const xmlChar *name){
	std::string elementName = (char*)name;
//	printf("EndElement %s\n", elementName.c_str());
	if(elementName == "key"){
		LHInfo::getInstance()->setIsKey(false);
	}
	else if(elementName == "dict"){
			LHInfo::getInstance()->setIsDict(false);
	}
	else if(elementName == "array"){
		LHInfo::getInstance()->substractFixtureArray();
	}		
	else {
		LHInfo::getInstance()->setCanPushValue(false);
	}
}
void read_characters(void *ctx, const xmlChar *ch, int len){
	std::string character((char*)ch,0,len);
	if(character[0] != '\n'){
	//	printf("Characters -%s-\n", character.c_str());
		LHInfo::getInstance()->setValue(character);
	}
	if(character == "JOINTS_INFO"){
		LHInfo::getInstance()->setReadJoint(true);
	}
	else if(character == "SPRITES_INFO"){
		LHInfo::getInstance()->setReadJoint(false);
	}
	else if(character == "GeneralProperties"){
		LHInfo::getInstance()->pushNewSpriteInfo();
		LHInfo::getInstance()->setBeginSpriteProperty();
	}
	else if(character == "PhysicProperties"){
		LHInfo::getInstance()->setBeginSpritePhysic();
	}
	else if(character == "ShapeFixtures"){
		LHInfo::getInstance()->setBeginFixtures();
	}
}